#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
主机名批量修改对话框模块 - 用于批量修改主机名
"""

import logging
import json
import os
import re
import openpyxl
from typing import Dict, List, Any, Optional
from PyQt5.QtWidgets import (
    QDialog, QVBoxLayout, QHBoxLayout, QLabel, 
    QLineEdit, QPushButton, QFormLayout, QDialogButtonBox,
    QComboBox, QSpinBox, QTabWidget, QWidget, QTextEdit,
    QCheckBox, QMessageBox, QTableWidget, QTableWidgetItem,
    QHeaderView, QGroupBox, QRadioButton, QProgressBar,
    QFileDialog, QProgressDialog
)
from PyQt5.QtCore import Qt, pyqtSlot, QThread, pyqtSignal
from PyQt5.QtGui import QFont
from openpyxl.utils import get_column_letter
from PyQt5.QtWidgets import QApplication


try:
    from src.zabbix_api import ZabbixAPI
except ImportError:
    # 尝试不同的导入路径
    from zabbix_api import ZabbixAPI

logger = logging.getLogger(__name__)

class ModHostnameDialog(QDialog):
    """主机名批量修改对话框"""
    
    def __init__(self, api: ZabbixAPI, parent=None):
        """
        初始化主机名批量修改对话框
        
        Args:
            api (ZabbixAPI): Zabbix API客户端
            parent: 父窗口
        """
        super().__init__(parent)
        self.api = api
        self.hosts_data = []
        self.setup_ui()
        self.load_hostgroups()
    
    def setup_ui(self):
        """设置UI界面"""
        self.setWindowTitle("批量修改主机名和可见名称")
        self.resize(1000, 650)
        self.setModal(True)
        
        # 创建主布局
        main_layout = QVBoxLayout(self)
        
        # 顶部区域 - 主机组选择
        top_group = QGroupBox("选择主机组")
        top_layout = QHBoxLayout(top_group)
        
        # 主机组下拉框
        self.group_combo = QComboBox()
        self.group_combo.setMinimumWidth(300)
        self.group_combo.currentIndexChanged.connect(self.on_group_changed)
        top_layout.addWidget(QLabel("主机组:"))
        top_layout.addWidget(self.group_combo)
        
        # 刷新按钮
        refresh_btn = QPushButton("刷新")
        refresh_btn.clicked.connect(self.load_hostgroups)
        top_layout.addWidget(refresh_btn)
        
        # 导出按钮
        export_btn = QPushButton("导出到Excel")
        export_btn.clicked.connect(self.export_to_excel)
        top_layout.addWidget(export_btn)
        
        # 导入按钮
        import_btn = QPushButton("从Excel导入")
        import_btn.clicked.connect(self.import_from_excel)
        top_layout.addWidget(import_btn)
        
        # 添加到主布局
        main_layout.addWidget(top_group)
        
        # 中间区域 - 主机表格
        middle_group = QGroupBox("主机列表")
        middle_layout = QVBoxLayout(middle_group)
        
        # 示例功能区域
        example_layout = QHBoxLayout()
        example_label = QLabel("示例修改:")
        example_layout.addWidget(example_label)
        
        # 添加"可见名称=主机名称_IP后两位"示例按钮
        name_ip_btn = QPushButton("可见名称=主机名称_IP后两位")
        name_ip_btn.clicked.connect(self.apply_hostname_ip_pattern)
        example_layout.addWidget(name_ip_btn)
        
        example_layout.addStretch()
        middle_layout.addLayout(example_layout)
        
        # 搜索框
        search_layout = QHBoxLayout()
        self.search_edit = QLineEdit()
        self.search_edit.setPlaceholderText("搜索主机")
        self.search_edit.textChanged.connect(self.filter_hosts)
        search_layout.addWidget(QLabel("搜索:"))
        search_layout.addWidget(self.search_edit)
        middle_layout.addLayout(search_layout)
        
        # 主机表格 - 修改列数和列标题
        self.host_table = QTableWidget(0, 4)
        self.host_table.setHorizontalHeaderLabels(["主机ID", "IP地址", "主机名称", "可见名称"])
        self.host_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
        self.host_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.host_table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        self.host_table.horizontalHeader().setSectionResizeMode(3, QHeaderView.Stretch)
        middle_layout.addWidget(self.host_table)
        
        main_layout.addWidget(middle_group, 4) # 增加表格区域比例
        
        # 底部区域 - 操作按钮和状态
        bottom_layout = QHBoxLayout()
        
        # 修改按钮
        self.apply_btn = QPushButton("应用修改")
        self.apply_btn.clicked.connect(self.apply_changes)
        self.apply_btn.setMinimumWidth(120)
        bottom_layout.addWidget(self.apply_btn)
        
        # 取消按钮
        cancel_btn = QPushButton("关闭")
        cancel_btn.clicked.connect(self.reject)
        cancel_btn.setMinimumWidth(120)
        bottom_layout.addWidget(cancel_btn)
        
        main_layout.addLayout(bottom_layout)
        
        # 状态区域 - 减小高度
        status_group = QGroupBox("操作日志")
        status_layout = QVBoxLayout(status_group)
        status_layout.setContentsMargins(5, 5, 5, 5) # 减小边距
        
        # 日志区域和清除按钮水平布局
        log_layout = QHBoxLayout()
        
        # 状态文本框 - 减小最大高度
        self.status_text = QTextEdit()
        self.status_text.setReadOnly(True)
        self.status_text.setMaximumHeight(80) # 减小高度
        # 设置等宽字体以便更好地显示日志
        font = QFont("Courier New")
        font.setPointSize(9)
        self.status_text.setFont(font)
        # 设置为白底黑字，提高可读性
        self.status_text.setStyleSheet("background-color: white; color: black;")
        log_layout.addWidget(self.status_text)
        
        # 添加清除日志按钮
        clear_log_btn = QPushButton("清除日志")
        clear_log_btn.setMaximumWidth(80)
        clear_log_btn.clicked.connect(lambda: self.status_text.clear())
        log_layout.addWidget(clear_log_btn)
        
        status_layout.addLayout(log_layout)
        
        main_layout.addWidget(status_group, 1) # 减小日志区域比例
    
    def log_message(self, message):
        """记录日志消息"""
        # 添加时间戳
        from datetime import datetime
        timestamp = datetime.now().strftime("%H:%M:%S")
        formatted_message = f"[{timestamp}] {message}"
        
        # 添加到状态文本
        self.status_text.append(formatted_message)
        self.status_text.verticalScrollBar().setValue(
            self.status_text.verticalScrollBar().maximum()
        )
        
        # 记录到日志系统
        logger.info(message)
    
    def load_hostgroups(self):
        """加载主机组列表"""
        try:
            self.log_message("正在加载主机组...")
            
            # 添加调试信息，查看API对象的方法
            self.log_message(f"API类型: {type(self.api).__name__}")
            api_methods = [method for method in dir(self.api) if not method.startswith('_')]
            self.log_message(f"可用的API方法: {', '.join(api_methods[:10])}...")
            
            # 尝试使用不同的API调用方式
            try:
                # 方式1: 直接调用API方法
                if hasattr(self.api, 'hostgroup'):
                    response = self.api.hostgroup.get(output=["groupid", "name"])
                    self.log_message("使用 api.hostgroup.get() 获取主机组")
                # 方式2: 使用get方法带参数
                elif hasattr(self.api, 'get'):
                    response = self.api.get('hostgroup', {'output': ["groupid", "name"]})
                    self.log_message("使用 api.get('hostgroup', params) 获取主机组")
                # 方式3: 使用do_request方法
                elif hasattr(self.api, 'do_request'):
                    response = self.api.do_request('hostgroup.get', {'output': ["groupid", "name"]})
                    self.log_message("使用 api.do_request() 获取主机组")
                # 方式4: 直接调用原始的hostgroup_get方法
                elif hasattr(self.api, 'hostgroup_get'):
                    response = self.api.hostgroup_get(output=["groupid", "name"])
                    self.log_message("使用 api.hostgroup_get() 获取主机组")
                # 方式5: 直接调用原始的get_host_groups方法
                elif hasattr(self.api, 'get_host_groups'):
                    response = self.api.get_host_groups()
                    self.log_message("使用 api.get_host_groups() 获取主机组")
                else:
                    self.log_message("找不到获取主机组的API方法，尝试向用户请求指定API方法名")
                    raise Exception("找不到获取主机组的API方法，请联系开发人员检查ZabbixAPI实现")
            except Exception as api_err:
                self.log_message(f"API调用失败: {str(api_err)}")
                # 尝试一种备选方案
                try:
                    # 旧版API可能会使用这个调用名称
                    response = self.api.hostgroups.get()
                    self.log_message("使用 api.hostgroups.get() 获取主机组")
                except:
                    raise api_err  # 如果备选方案也失败，则抛出原始错误
            
            # 处理结果
            self.log_message(f"API调用成功，响应类型: {type(response).__name__}")
            
            # 尝试解析响应
            if isinstance(response, dict) and "result" in response:
                groups = response["result"]
            elif isinstance(response, list):
                groups = response
            else:
                groups = response
            
            self.log_message(f"解析到 {len(groups) if groups else 0} 个主机组")
            
            # 添加到下拉框
            self.group_combo.clear()
            self.group_combo.addItem("-- 请选择主机组 --", "")
            
            try:
                # 尝试对组进行排序
                for group in sorted(groups, key=lambda g: g.get('name', '')):
                    self.group_combo.addItem(group.get('name', ''), group.get('groupid', ''))
            except Exception as sort_err:
                # 如果排序失败，就不排序
                self.log_message(f"排序失败: {str(sort_err)}，使用原始顺序")
                for group in groups:
                    self.group_combo.addItem(group.get('name', ''), group.get('groupid', ''))
            
            self.log_message(f"已加载 {len(groups) if groups else 0} 个主机组")
            
        except Exception as e:
            QMessageBox.warning(self, "错误", f"加载主机组失败: {str(e)}")
            self.log_message(f"加载主机组失败: {str(e)}")
            logger.error(f"加载主机组失败: {str(e)}")
    
    def on_group_changed(self, index):
        """主机组选择变化处理"""
        if index <= 0:
            # 清空主机表格
            self.host_table.setRowCount(0)
            self.hosts_data = []
            return
        
        self.load_hosts()
    
    def load_hosts(self):
        """加载主机列表"""
        # 获取选中的主机组ID
        group_id = self.group_combo.currentData()
        group_name = self.group_combo.currentText()
        
        if not group_id:
            return
        
        try:
            self.log_message(f"正在加载主机组 '{group_name}' (ID: {group_id}) 的主机...")
            
            # 尝试使用不同的API调用方式获取主机
            try:
                # 方式1: 通过host对象调用，使用extend获取完整数据
                if hasattr(self.api, 'host'):
                    response = self.api.host.get(
                        groupids=[group_id],
                        output="extend"
                    )
                    self.log_message("使用 api.host.get() 获取主机")
                # 方式2: 使用get方法带参数
                elif hasattr(self.api, 'get'):
                    response = self.api.get('host', {
                        'groupids': [group_id],
                        'output': "extend"
                    })
                    self.log_message("使用 api.get('host', params) 获取主机")
                # 方式3: 使用do_request方法
                elif hasattr(self.api, 'do_request'):
                    response = self.api.do_request('host.get', {
                        'groupids': [group_id],
                        'output': "extend"
                    })
                    self.log_message("使用 api.do_request() 获取主机")
                # 方式4: 直接调用原始的host_get方法
                elif hasattr(self.api, 'host_get'):
                    response = self.api.host_get(
                        groupids=[group_id],
                        output="extend"
                    )
                    self.log_message("使用 api.host_get() 获取主机")
                # 方式5: 直接使用JSON-RPC请求
                elif hasattr(self.api, 'auth'):
                    # 使用与用户提供的示例相似的请求
                    json_request = {
                        "jsonrpc": "2.0",
                        "method": "host.get",
                        "params": {
                            "output": "extend",
                            "groupids": [group_id]
                        },
                        "auth": self.api.auth,
                        "id": 1
                    }
                    
                    # 如果API有json_request方法，使用它
                    if hasattr(self.api, 'json_request'):
                        response = self.api.json_request(json_request)
                        self.log_message("使用 api.json_request() 获取主机")
                    # 否则尝试使用requests库直接发送请求
                    elif hasattr(self.api, 'url'):
                        import requests
                        url = self.api.url
                        headers = {'Content-Type': 'application/json-rpc'}
                        r = requests.post(url, json=json_request, headers=headers)
                        response = r.json()
                        self.log_message("使用直接HTTP请求获取主机")
                    else:
                        raise Exception("找不到合适的API调用方法")
                # 方式6: 原始方法
                elif hasattr(self.api, 'get_hosts_by_group'):
                    response = self.api.get_hosts_by_group(group_id)
                    self.log_message("使用 api.get_hosts_by_group() 获取主机")
                elif hasattr(self.api, 'get_hosts_by_group_ids'):
                    response = self.api.get_hosts_by_group_ids([group_id])
                    self.log_message("使用 api.get_hosts_by_group_ids() 获取主机")
                else:
                    raise Exception("找不到获取主机的API方法，请联系开发人员检查ZabbixAPI实现")
            except Exception as api_err:
                self.log_message(f"API调用失败: {str(api_err)}")
                # 尝试一种备选方案
                try:
                    # 旧版API可能会使用这个调用名称
                    response = self.api.hosts.get(groupids=[group_id], output="extend")
                    self.log_message("使用 api.hosts.get() 获取主机")
                except:
                    raise api_err  # 如果备选方案也失败，则抛出原始错误
            
            # 处理结果
            self.log_message(f"API调用成功，响应类型: {type(response).__name__}")
            
            # 打印样例数据帮助调试
            if isinstance(response, dict) and 'result' in response and response['result']:
                sample_host = response['result'][0]
                self.log_message(f"返回数据示例: {str(sample_host)[:200]}...")
                self.log_message(f"主机示例 - ID: {sample_host.get('hostid')}, 主机名: {sample_host.get('host')}, 可见名称: {sample_host.get('name')}")
            elif isinstance(response, list) and response:
                sample_host = response[0]
                self.log_message(f"返回数据示例: {str(sample_host)[:200]}...")
                self.log_message(f"主机示例 - ID: {sample_host.get('hostid')}, 主机名: {sample_host.get('host')}, 可见名称: {sample_host.get('name')}")
            
            # 尝试解析响应
            if isinstance(response, dict) and "result" in response:
                hosts = response["result"]
            elif isinstance(response, list):
                hosts = response
            else:
                hosts = response
            
            self.log_message(f"解析到 {len(hosts) if hosts else 0} 台主机")
            self.hosts_data = hosts if hosts else []
            
            # 获取所有主机ID
            hostids = [host.get('hostid') for host in self.hosts_data]
            
            # 创建主机ID到IP的映射
            host_ips = {}
            
            # 使用hostinterface.get API获取主机IP
            if hostids:
                try:
                    self.log_message(f"正在获取 {len(hostids)} 台主机的IP地址...")
                    
                    # 准备API调用
                    if hasattr(self.api, 'hostinterface') and hasattr(self.api.hostinterface, 'get'):
                        interfaces = self.api.hostinterface.get(
                            hostids=hostids,
                            output="extend"
                        )
                        self.log_message("使用 api.hostinterface.get() 获取主机接口")
                    elif hasattr(self.api, 'do_request'):
                        interfaces = self.api.do_request('hostinterface.get', {
                            'hostids': hostids,
                            'output': "extend"
                        })
                        if isinstance(interfaces, dict) and "result" in interfaces:
                            interfaces = interfaces["result"]
                        self.log_message("使用 api.do_request() 获取主机接口")
                    elif hasattr(self.api, 'auth') and hasattr(self.api, 'url'):
                        # 使用直接的JSON-RPC调用
                        json_request = {
                            "jsonrpc": "2.0",
                            "method": "hostinterface.get",
                            "params": {
                                "output": "extend",
                                "hostids": hostids
                            },
                            "auth": self.api.auth,
                            "id": 1
                        }
                        
                        # 如果API有json_request方法，使用它
                        if hasattr(self.api, 'json_request'):
                            response = self.api.json_request(json_request)
                            interfaces = response.get("result", [])
                            self.log_message("使用 api.json_request() 获取主机接口")
                        # 否则尝试使用requests库直接发送请求
                        else:
                            import requests
                            url = self.api.url
                            headers = {'Content-Type': 'application/json-rpc'}
                            r = requests.post(url, json=json_request, headers=headers)
                            response = r.json()
                            interfaces = response.get("result", [])
                            self.log_message("使用直接HTTP请求获取主机接口")
                    else:
                        self.log_message("无法找到合适的方法获取主机接口")
                        interfaces = []
                    
                    # 记录找到的接口数量
                    self.log_message(f"找到 {len(interfaces) if interfaces else 0} 个主机接口")
                    
                    # 如果成功获取接口数据，创建主机ID到IP的映射
                    if interfaces:
                        for interface in interfaces:
                            hostid = interface.get('hostid')
                            ip = interface.get('ip')
                            # 不过滤127.0.0.1地址
                            if hostid and ip:
                                if hostid not in host_ips:
                                    host_ips[hostid] = []
                                host_ips[hostid].append(ip)
                        
                        self.log_message(f"处理完成，为 {len(host_ips)} 台主机找到了IP地址")
                except Exception as interface_err:
                    self.log_message(f"获取主机接口时出错: {str(interface_err)}")
                    self.log_message("将继续而不显示IP地址")
            
            # 清空表格
            self.host_table.setRowCount(0)
            
            # 添加到表格 - 调整表格列顺序和内容
            for i, host in enumerate(self.hosts_data):
                self.host_table.insertRow(i)
                
                # 主机ID
                host_id = host.get('hostid', '')
                id_item = QTableWidgetItem(host_id)
                id_item.setFlags(id_item.flags() & ~Qt.ItemIsEditable)
                self.host_table.setItem(i, 0, id_item)
                
                # IP地址列 - 显示获取到的IP地址或默认消息
                ip_text = ", ".join(host_ips.get(host_id, [])) if host_id in host_ips else "-"
                ip_item = QTableWidgetItem(ip_text)
                if ip_text == "-":
                    ip_item.setToolTip("未找到此主机的IP地址信息")
                ip_item.setFlags(ip_item.flags() & ~Qt.ItemIsEditable)
                self.host_table.setItem(i, 1, ip_item)
                
                # 主机名称 (host) - 不可编辑
                host_name = host.get('host', '')
                host_item = QTableWidgetItem(host_name)
                host_item.setFlags(host_item.flags() & ~Qt.ItemIsEditable)
                self.host_table.setItem(i, 2, host_item)
                
                # 可见名称 (name) - 可编辑
                visible_name = host.get('name', '')
                visible_item = QTableWidgetItem(visible_name)
                self.host_table.setItem(i, 3, visible_item)
            
            self.log_message(f"已加载 {len(self.hosts_data)} 台主机")
            
        except Exception as e:
            QMessageBox.warning(self, "错误", f"加载主机失败: {str(e)}")
            self.log_message(f"加载主机失败: {str(e)}")
            logger.error(f"加载主机失败: {str(e)}")
    
    def filter_hosts(self, text):
        """过滤主机列表"""
        text = text.lower()
        for i in range(self.host_table.rowCount()):
            host_id = self.host_table.item(i, 0).text().lower()
            ip = self.host_table.item(i, 1).text().lower()
            hostname = self.host_table.item(i, 2).text().lower()
            visible_name = self.host_table.item(i, 3).text().lower()
            
            self.host_table.setRowHidden(
                i, text and text not in host_id and text not in ip and text not in hostname and text not in visible_name
            )
    
    def export_to_excel(self):
        """导出数据到Excel文件"""
        try:
            file_path, _ = QFileDialog.getSaveFileName(
                self, "保存Excel文件", "", "Excel文件 (*.xlsx)")
            
            if not file_path:
                return
                
            # 创建工作簿和工作表
            workbook = openpyxl.Workbook()
            sheet = workbook.active
            sheet.title = "主机信息"
            
            # 写入表头
            headers = ["主机ID", "IP地址", "主机名称", "可见名称"]
            for col, header in enumerate(headers, 1):
                sheet.cell(row=1, column=col).value = header
                
            # 写入数据
            row = 2
            for i in range(self.host_table.rowCount()):
                if self.host_table.isRowHidden(i):
                    continue
                    
                # 导出表格中数据
                hostid = self.host_table.item(i, 0).text()
                
                # 确保所有值都被正确提取，即使某些单元格为空
                hostid_item = self.host_table.item(i, 0)
                ip_item = self.host_table.item(i, 1)
                hostname_item = self.host_table.item(i, 2)
                visible_name_item = self.host_table.item(i, 3)
                
                hostid = hostid_item.text() if hostid_item else ""
                ip = ip_item.text() if ip_item else ""
                hostname = hostname_item.text() if hostname_item else ""
                visible_name = visible_name_item.text() if visible_name_item else ""
                
                # 如果某些值为空，尝试从hosts_data中获取
                if not (ip and hostname and visible_name):
                    for host in self.hosts_data:
                        if host.get('hostid') == hostid:
                            if not ip:
                                ip = host.get('ip', "")
                            if not hostname:
                                hostname = host.get('host', "")
                            if not visible_name:
                                visible_name = host.get('name', hostname)  # 如果可见名称为空，使用主机名
                            break
                
                # 写入Excel
                sheet.cell(row=row, column=1).value = hostid
                sheet.cell(row=row, column=2).value = ip
                sheet.cell(row=row, column=3).value = hostname
                sheet.cell(row=row, column=4).value = visible_name
                row += 1
                
            # 调整列宽
            for col in range(1, 5):
                sheet.column_dimensions[get_column_letter(col)].width = 20
                
            # 保存文件
            workbook.save(file_path)
            self.log_message(f"成功导出数据到 {file_path}")
            QMessageBox.information(self, "导出成功", f"成功导出数据到 {file_path}")
            
        except Exception as e:
            QMessageBox.warning(self, "导出失败", f"导出数据时出错: {str(e)}")
            self.log_message(f"导出数据时出错: {str(e)}")
            logger.error(f"导出数据时出错: {str(e)}")
    
    def import_from_excel(self):
        """从Excel导入主机名修改"""
        # 获取Excel文件路径
        file_path, _ = QFileDialog.getOpenFileName(
            self,
            "打开Excel文件",
            "",
            "Excel 文件 (*.xlsx)"
        )
        
        if not file_path:
            return
        
        try:
            # 打开Excel文件
            workbook = openpyxl.load_workbook(file_path)
            sheet = workbook.active
            
            # 验证表头
            headers = [cell.value for cell in sheet[1]]
            required_headers = ["主机ID", "IP地址", "主机名称", "可见名称"]
            
            missing_headers = [h for h in required_headers if h not in headers]
            if missing_headers:
                QMessageBox.warning(self, "格式错误", f"Excel文件缺少必要的列: {', '.join(missing_headers)}")
                return
            
            # 查找列索引
            hostid_idx = headers.index("主机ID") + 1  # Excel列从1开始
            ip_idx = headers.index("IP地址") + 1
            hostname_idx = headers.index("主机名称") + 1
            visible_name_idx = headers.index("可见名称") + 1
            
            # 读取数据
            data = []
            for row in range(2, sheet.max_row + 1):  # 从第2行开始
                hostid = sheet.cell(row=row, column=hostid_idx).value
                hostname = sheet.cell(row=row, column=hostname_idx).value
                visible_name = sheet.cell(row=row, column=visible_name_idx).value
                
                # 检查是否存在修改（与当前表格中的值比较）
                if hostid:
                    for i in range(self.host_table.rowCount()):
                        if self.host_table.item(i, 0).text() == str(hostid):
                            current_visible = self.host_table.item(i, 3).text()
                            if visible_name and visible_name != current_visible:
                                data.append({
                                    "hostid": hostid,
                                    "hostname": hostname,
                                    "visible_name": visible_name
                                })
                                break
            
            if not data:
                QMessageBox.information(self, "导入完成", "没有找到需要修改的数据")
                return
            
            # 更新表格
            for item in data:
                hostid = str(item["hostid"])
                visible_name = item["visible_name"]
                
                for i in range(self.host_table.rowCount()):
                    if self.host_table.item(i, 0).text() == hostid:
                        self.host_table.item(i, 3).setText(visible_name)
                        break
            
            self.log_message(f"从Excel导入了 {len(data)} 条修改数据")
            QMessageBox.information(self, "导入成功", f"成功导入 {len(data)} 条修改数据")
            
        except Exception as e:
            QMessageBox.warning(self, "错误", f"导入失败: {str(e)}")
            self.log_message(f"导入失败: {str(e)}")
            logger.error(f"导入失败: {str(e)}")
    
    def apply_changes(self):
        """应用主机名修改"""
        # 收集修改数据
        changes = []
        for i in range(self.host_table.rowCount()):
            if self.host_table.isRowHidden(i):
                continue
                
            hostid = self.host_table.item(i, 0).text()
            hostname = self.host_table.item(i, 2).text()  # 主机名称(host)
            visible_name = self.host_table.item(i, 3).text()  # 可见名称(name)
            
            # 检查是否有修改（与原始数据比较）
            for host in self.hosts_data:
                if host.get('hostid') == hostid:
                    original_visible = host.get('name', '')
                    if visible_name != original_visible:
                        changes.append({
                            "hostid": hostid,
                            "hostname": hostname,
                            "current_visible": original_visible,
                            "new_visible": visible_name
                        })
                    break
        
        if not changes:
            QMessageBox.information(self, "提示", "没有需要应用的修改")
            return
        
        # 确认修改
        reply = QMessageBox.question(
            self,
            "确认修改",
            f"将修改 {len(changes)} 个主机的可见名称，此操作不可撤销。确定要继续吗？",
            QMessageBox.Yes | QMessageBox.No,
            QMessageBox.No
        )
        
        if reply != QMessageBox.Yes:
            return
        
        # 执行修改
        success_count = 0
        error_count = 0
        
        self.log_message(f"开始应用 {len(changes)} 条修改...")
        
        # 创建进度对话框
        progress = QProgressDialog("正在应用更改...", "取消", 0, len(changes), self)
        progress.setWindowTitle("正在更新主机")
        progress.setMinimumDuration(0)
        progress.setValue(0)
        
        for index, change in enumerate(changes):
            # 更新进度
            progress.setValue(index)
            QApplication.processEvents()
            
            if progress.wasCanceled():
                self.log_message("用户取消了更新操作")
                break
                
            try:
                hostid = change["hostid"]
                hostname = change["hostname"]
                current_visible = change["current_visible"]
                new_visible = change["new_visible"]
                
                self.log_message(f"正在修改主机 {hostname} (ID: {hostid}): 可见名称 {current_visible} -> {new_visible}")
                
                # 准备更新参数 - 使用推荐的简化格式
                update_params = {
                    "hostid": hostid,
                    "name": new_visible  # name参数对应可见名称
                }
                
                self.log_message(f"使用参数: {json.dumps(update_params)}")
                
                result = None
                
                # 确定API的类型和方法
                api_type = type(self.api).__name__
                self.log_message(f"API类型: {api_type}")
                
                # 列出API对象上的可用方法
                api_methods = [method for method in dir(self.api) if not method.startswith('_')]
                self.log_message(f"可用API方法: {', '.join(api_methods)}")
                
                # 尝试最常见的API方法
                if hasattr(self.api, 'host') and hasattr(self.api.host, 'update'):
                    self.log_message("使用 api.host.update() 方法更新主机")
                    result = self.api.host.update(**update_params)
                elif hasattr(self.api, 'do_request'):
                    self.log_message("使用 api.do_request() 方法更新主机")
                    result = self.api.do_request('host.update', update_params)
                elif hasattr(self.api, 'call'):
                    self.log_message("使用 api.call() 方法更新主机")
                    result = self.api.call('host.update', update_params)
                elif hasattr(self.api, 'json_rpc'):
                    self.log_message("使用 api.json_rpc() 方法更新主机")
                    result = self.api.json_rpc('host.update', update_params)
                elif hasattr(self.api, 'update_host'):
                    self.log_message("使用 api.update_host() 方法更新主机")
                    result = self.api.update_host(hostid, visible_name=new_visible)
                else:
                    # 尝试直接API调用作为最后手段
                    import requests
                    self.log_message("尝试直接发送API请求")
                    
                    if hasattr(self.api, 'url') and (hasattr(self.api, 'auth') or hasattr(self.api, 'auth_token')):
                        url = self.api.url
                        auth = getattr(self.api, 'auth', None) or getattr(self.api, 'auth_token', None)
                        
                        update_data = {
                            "jsonrpc": "2.0",
                            "method": "host.update",
                            "params": update_params,
                            "auth": auth,
                            "id": index + 1
                        }
                        
                        headers = {'Content-Type': 'application/json-rpc'}
                        self.log_message(f"发送请求到 {url}，数据: {json.dumps(update_data)}")
                        
                        r = requests.post(url, json=update_data, headers=headers)
                        result = r.json()
                        self.log_message(f"API响应: {json.dumps(result)}")
                    else:
                        raise Exception("找不到有效的API方法和必要的信息来更新主机")
                
                # 详细记录结果
                if result:
                    self.log_message(f"API返回结果: {json.dumps(result) if isinstance(result, (dict, list)) else str(result)}")
                
                # 分析结果判断是否成功
                success = False
                if isinstance(result, dict):
                    if "result" in result:
                        if isinstance(result["result"], dict) and "hostids" in result["result"]:
                            hostids = result["result"]["hostids"]
                            success = hostid in hostids or str(hostid) in hostids
                        else:
                            success = bool(result["result"])
                    elif "hostids" in result:
                        hostids = result["hostids"]
                        success = hostid in hostids or str(hostid) in hostids
                elif isinstance(result, list) and len(result) > 0:
                    success = True
                else:
                    success = bool(result)
                
                if success:
                    success_count += 1
                    self.log_message(f"成功修改主机 {hostname}: {current_visible} -> {new_visible}")
                    
                    # 更新hosts_data中的值
                    for host in self.hosts_data:
                        if host.get('hostid') == hostid:
                            host['name'] = new_visible
                            break
                else:
                    error_msg = "API调用成功但未返回预期结果"
                    if isinstance(result, dict) and "error" in result:
                        error_msg = f"API错误: {result['error'].get('message', '未知错误')}, 代码: {result['error'].get('code', '未知')}"
                    
                    self.log_message(f"修改主机 {hostname} 失败: {error_msg}")
                    error_count += 1
                
            except Exception as e:
                self.log_message(f"修改主机 {hostname} 时出错: {str(e)}")
                error_count += 1
                logger.error(f"修改主机失败: {str(e)}")
                import traceback
                trace = traceback.format_exc()
                self.log_message(f"错误详情: {trace}")
                logger.error(f"错误堆栈: {trace}")
        
        # 关闭进度对话框
        progress.setValue(len(changes))
        
        # 显示结果
        self.log_message(f"修改完成，成功: {success_count}，失败: {error_count}")
        
        if error_count == 0 and success_count > 0:
            QMessageBox.information(self, "修改完成", f"成功修改 {success_count} 个主机的可见名称")
        elif success_count > 0:
            QMessageBox.warning(self, "部分修改成功", f"成功修改 {success_count} 个主机，失败 {error_count} 个\n详情请查看日志")
        else:
            QMessageBox.critical(self, "修改失败", f"所有 {error_count} 个主机修改失败\n请检查API连接和权限，详情请查看日志")

    def apply_hostname_ip_pattern(self):
        """应用主机名称_IP后两位作为可见名称"""
        self.log_message("开始应用主机名称_IP后两位作为可见名称...")
        
        try:
            changed_count = 0
            
            for i in range(self.host_table.rowCount()):
                if self.host_table.isRowHidden(i):
                    continue
                
                hostid = self.host_table.item(i, 0).text()
                hostname = self.host_table.item(i, 2).text()
                ip = self.host_table.item(i, 1).text()
                
                if ip:
                    # 提取IP地址的最后一个部分（最后的八位数）
                    ip_parts = ip.split('.')
                    if len(ip_parts) == 4:  # 标准IPv4地址
                        # 使用最后两个部分或最后一个部分的值
                        if len(ip_parts) >= 3:
                            ip_suffix = f"{ip_parts[-2]}.{ip_parts[-1]}"
                        else:
                            ip_suffix = ip_parts[-1]
                        visible_name = f"{hostname}_{ip_suffix}"
                    else:
                        # 非标准IP格式，使用完整IP
                        visible_name = f"{hostname}_{ip}"
                else:
                    visible_name = hostname
                
                # 检查是否与当前名称不同
                current_name = self.host_table.item(i, 3).text()
                if current_name != visible_name:
                    # 只更新表格中的可见名称，不更新hosts_data
                    self.host_table.item(i, 3).setText(visible_name)
                    changed_count += 1
            
            if changed_count > 0:
                self.log_message(f"主机名称_IP后两位作为可见名称应用完成，共修改了 {changed_count} 个主机")
                QMessageBox.information(self, "修改完成", f"已将 {changed_count} 个主机的可见名称设置为主机名称_IP后两位\n请点击\"应用修改\"按钮将更改保存到Zabbix服务器")
            else:
                self.log_message("没有需要修改的主机")
                QMessageBox.information(self, "提示", "没有需要修改的主机")
            
        except Exception as e:
            QMessageBox.warning(self, "错误", f"应用主机名称_IP后两位作为可见名称时出错: {str(e)}")
            self.log_message(f"应用主机名称_IP后两位作为可见名称时出错: {str(e)}")
            logger.error(f"应用主机名称_IP后两位作为可见名称时出错: {str(e)}") 